#include "XMLWriter.h"

void NahidaProject::XMLWriterNode::RemoveIllegalChars(std::string& m_String) {
	static std::unordered_map<char, std::string> m_CharsMap = { { '<', "&lt;" }, { '>', "&gt;" }, { '&', "&amp;" }, { '\'', "&apos;" }, { '\"', "&quot;" } };

	size_t m_Pos = 0;
	while (m_String.size() > m_Pos){
		auto m_Itter = m_CharsMap.find(m_String[m_Pos]);
		if (m_Itter != m_CharsMap.end()){
			m_String.replace(m_Pos, 1, m_Itter->second);
			m_Pos += m_Itter->second.size();
		}
		else {
			++m_Pos;
		}
	}
}

NahidaProject::XMLWriterNode& NahidaProject::XMLWriterNode::operator=(const char* m_Value){
	Value = m_Value;
	RemoveIllegalChars(Value);
	return *this;
}

NahidaProject::XMLWriterNode& NahidaProject::XMLWriterNode::operator[](const char* m_Key){
	XMLWriterNode& m_Node = Nodes[m_Key];
	m_Node.Key = m_Key;
	m_Node.Depth = Depth + 1;

	return m_Node;
}

NahidaProject::XMLWriterNode& NahidaProject::XMLWriterNode::operator()(const char* m_AttributeKey, const char* m_AttributeValue){
	Attributes[m_AttributeKey] = m_AttributeValue;
	RemoveIllegalChars(Attributes[m_AttributeKey]);
	return *this;
}

std::string NahidaProject::XMLWriterNode::GetKey(){
	size_t m_HashTag = Key.find_first_of("##");
	if (m_HashTag == std::string::npos)
		return Key;

	return Key.substr(0, m_HashTag);
}

std::string NahidaProject::XMLWriterNode::GetOpenTag(){
	std::string m_String = "<" + GetKey();

	for (auto& m_Attribute : Attributes)
		m_String += " " + m_Attribute.first + "=\"" + m_Attribute.second + "\"";

	return (m_String + ">");
}

std::string NahidaProject::XMLWriterNode::GetCloseTag() {
	return ("</" + GetKey() + ">");
}

void NahidaProject::XMLWriter::BuildString(std::string& m_String, XMLWriterNode& m_Node){
	for (auto& m_Nodes : m_Node.Nodes){
		XMLWriterNode& m_NextNode = m_Nodes.second;

		std::string m_Tabs(m_NextNode.Depth - 1, '\t');

		std::string m_OpenTag = m_NextNode.GetOpenTag();
		std::string m_CloseTag = m_NextNode.GetCloseTag();

		if (m_NextNode.Nodes.empty())
		{
			if (m_NextNode.Value.empty())
			{
				m_OpenTag.pop_back();
				m_String += m_Tabs + m_OpenTag + "/>\n";
			}
			else
				m_String += m_Tabs + m_OpenTag + m_NextNode.Value + m_CloseTag + "\n";
		}
		else
		{
			m_String += m_Tabs + m_OpenTag + "\n";
			if (!m_NextNode.Value.empty())
				m_String += m_Tabs + "\t" + m_NextNode.Value + "\n";

			BuildString(m_String, m_NextNode);
			m_String += m_Tabs + m_CloseTag + "\n";
		}
	}
}

NahidaProject::XMLWriter::operator std::string(){
	std::string m_String = (m_InsertHeader ? GetHeader() : "");
	BuildString(m_String, m_Node);

	return m_String;
}

std::string NahidaProject::XMLWriter::ToString() { 
	return operator std::string(); 
}

bool NahidaProject::XMLWriter::OutputFile(const char* m_Path){
	FILE* m_File = fopen(m_Path, "w");
	if (!m_File)
		return false;

	std::string m_String = ToString();
	fwrite(&m_String[0], sizeof(char), m_String.size(), m_File);
	fclose(m_File);

	return true;
}